namespace DotNetNuke.Services.Search
{
    using DotNetNuke.Common;
    using DotNetNuke.Common.Utilities;
    using DotNetNuke.Data;
    using DotNetNuke.Entities.Modules;
    using DotNetNuke.Entities.Portals;
    using DotNetNuke.Entities.Tabs;
    using DotNetNuke.Security;
    using DotNetNuke.Services.Exceptions;
    using Microsoft.VisualBasic;
    using Microsoft.VisualBasic.CompilerServices;
    using System;
    using System.Collections;
    using System.Data;
    using System.Runtime.CompilerServices;

    /// -----------------------------------------------------------------------------
    /// Namespace:  DotNetNuke.Services.Search
    /// Project:    DotNetNuke.Search.DataStore
    /// Class:      SearchDataStore
    /// -----------------------------------------------------------------------------
    /// <summary>
    /// The SearchDataStore is an implementation of the abstract SearchDataStoreProvider
    /// class
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// [cnurse]	11/15/2004	documented
    /// </history>
    /// -----------------------------------------------------------------------------
    public class SearchDataStore : SearchDataStoreProvider
    {
        private Hashtable _defaultSettings;
        private Hashtable _settings;
        private bool includeCommon = false;
        private bool includeNumbers = true;
        private int maxWordLength = 50;
        private int minWordLength = 4;

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// AddIndexWords adds the Index Words to the Data Store
        /// </summary>
        /// <remarks>
        /// </remarks>
        /// <param name="IndexId">The Id of the SearchItem</param>
        /// <param name="SearchItem">The SearchItem</param>
        /// <param name="Language">The Language of the current Item</param>
        /// <history>
        /// [cnurse]	11/15/2004	documented
        /// [cnurse]    11/16/2004  replaced calls to separate content clean-up
        /// functions with new call to HtmlUtils.Clean().
        /// replaced logic to determine whether word should
        /// be indexed by call to CanIndexWord()
        /// </history>
        /// -----------------------------------------------------------------------------
        private void AddIndexWords(int IndexId, SearchItemInfo SearchItem, string Language)
        {
            IEnumerator refObjectHelperL0=null;
            Hashtable IndexWords = new Hashtable();
            Hashtable IndexPositions = new Hashtable();
            this._settings = SearchDataStoreController.GetSearchSettings(SearchItem.ModuleId);
            string setting = this.GetSetting("MaxSearchWordLength");
            if (setting != "")
            {
                this.maxWordLength = int.Parse(setting);
            }
            setting = this.GetSetting("MinSearchWordLength");
            if (setting != "")
            {
                this.minWordLength = int.Parse(setting);
            }
            if (this.GetSetting("SearchIncludeCommon") == "Y")
            {
                this.includeCommon = true;
            }
            if (this.GetSetting("SearchIncludeNumeric") == "N")
            {
                this.includeNumbers = false;
            }
            int intWord=0;
            foreach (string strWordLocal in Strings.Split(HtmlUtils.Clean(SearchItem.Content, true).ToLower(), " ", -1, CompareMethod.Binary))
            {
                if (this.CanIndexWord(strWordLocal, Language))
                {                   
                    intWord++;
                    if (!IndexWords.ContainsKey(strWordLocal))
                    {
                        IndexWords.Add(strWordLocal, 0);
                        IndexPositions.Add(strWordLocal, 1);
                    }
                    IndexWords[strWordLocal] = Conversions.ToInteger(IndexWords[strWordLocal]) + 1;
                    IndexPositions[strWordLocal] = Conversions.ToString(IndexPositions[strWordLocal]) + "," + intWord.ToString();
                }
            }
            Hashtable Words = this.GetSearchWords();
            string strWord = "";
            try
            {
                refObjectHelperL0 = IndexWords.Keys.GetEnumerator();
                while (refObjectHelperL0.MoveNext())
                {
                    int WordId;
                    strWord = Conversions.ToString(RuntimeHelpers.GetObjectValue(refObjectHelperL0.Current));
                    if (Words.ContainsKey(strWord))
                    {
                        WordId = Conversions.ToInteger(Words[strWord]);
                    }
                    else
                    {
                        WordId = DataProvider.Instance().AddSearchWord(strWord);
                        Words.Add(strWord, WordId);
                    }
                    int SearchItemWordID = DataProvider.Instance().AddSearchItemWord(IndexId, WordId, Conversions.ToInteger(IndexWords[strWord]));
                    DataProvider.Instance().AddSearchItemWordPosition(SearchItemWordID, Conversions.ToString(IndexPositions[strWord]));
                }
            }
            finally
            {
                if (refObjectHelperL0 is IDisposable)
                {
                    (refObjectHelperL0 as IDisposable).Dispose();
                }
            }
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// CanIndexWord determines whether the Word should be indexed
        /// </summary>
        /// <remarks>
        /// </remarks>
        /// <param name="strWord">The Word to validate</param>
        /// <returns>True if indexable, otherwise false</returns>
        /// <history>
        /// [cnurse]	11/16/2004	created
        /// </history>
        /// -----------------------------------------------------------------------------
        private bool CanIndexWord(string strWord, string Locale)
        {
            bool retValue = true;
            Hashtable CommonWords = this.GetCommonWords(Locale);
            if (Versioned.IsNumeric(strWord))
            {
                if (!this.includeNumbers)
                {
                    retValue = false;
                }
                return retValue;
            }
            if ((strWord.Length < this.minWordLength) | (strWord.Length > this.maxWordLength))
            {
                return false;
            }
            if (CommonWords.ContainsKey(strWord) & !this.includeCommon)
            {
                retValue = false;
            }
            return retValue;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// GetCommonWords gets a list of the Common Words for the locale
        /// </summary>
        /// <remarks>
        /// </remarks>
        /// <param name="Locale">The locale string</param>
        /// <returns>A hashtable of common words</returns>
        /// <history>
        /// [cnurse]	11/15/2004	documented
        /// </history>
        /// -----------------------------------------------------------------------------
        private Hashtable GetCommonWords(string Locale)
        {
            string strCacheKey = "CommonWords" + Locale;
            Hashtable objWords = (Hashtable) DataCache.GetCache(strCacheKey);
            if (objWords == null)
            {
                objWords = new Hashtable();
                IDataReader drWords = DataProvider.Instance().GetSearchCommonWordsByLocale(Locale);
                try
                {
                    while (drWords.Read())
                    {
                        objWords.Add(drWords["CommonWord"].ToString(), drWords["CommonWord"].ToString());
                    }
                }
                finally
                {
                    drWords.Close();
                    drWords.Dispose();
                }
                DataCache.SetCache(strCacheKey, objWords);
            }
            return objWords;
        }

        private SearchItemInfoCollection GetSearchItems(int ModuleId)
        {
            return new SearchItemInfoCollection(CBO.FillCollection(DataProvider.Instance().GetSearchItems(Null.NullInteger, Null.NullInteger, ModuleId), typeof(SearchItemInfo)));
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// GetSearchItems gets a collection of Search Items for a Module/Tab/Portal
        /// </summary>
        /// <remarks>
        /// </remarks>
        /// <param name="PortalID">A Id of the Portal</param>
        /// <param name="TabID">A Id of the Tab</param>
        /// <param name="ModuleID">A Id of the Module</param>
        /// <history>
        /// [cnurse]	11/15/2004	documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public override SearchResultsInfoCollection GetSearchItems(int PortalID, int TabID, int ModuleID)
        {
            return new SearchResultsInfoCollection(CBO.FillCollection(DataProvider.Instance().GetSearchItems(PortalID, TabID, ModuleID), typeof(SearchResultsInfo)));
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// GetSearchResults gets the search results for a passed in criteria string
        /// </summary>
        /// <remarks>
        /// </remarks>
        /// <param name="PortalID">A Id of the Portal</param>
        /// <param name="Criteria">The criteria string</param>
        /// <history>
        /// [cnurse]	11/15/2004	documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public override SearchResultsInfoCollection GetSearchResults(int PortalID, string Criteria)
        {
            IEnumerator refObjectHelperL0=null;
            IEnumerator refObjectHelperL7=null;
            PortalController objPortalController = new PortalController();
            string locale = objPortalController.GetPortal(PortalID).DefaultLanguage;
            Hashtable CommonWords = this.GetCommonWords(locale);
            Criteria = Criteria.ToLower();
            SearchCriteriaCollection SearchWords = new SearchCriteriaCollection(Criteria);
            Hashtable SearchResults = new Hashtable();
            try
            {
                refObjectHelperL0 = SearchWords.GetEnumerator();
                while (refObjectHelperL0.MoveNext())
                {
                    SearchCriteria Criterion = (SearchCriteria) refObjectHelperL0.Current;
                    if (!CommonWords.ContainsKey(Criterion.Criteria))
                    {
                        SearchResultsInfoCollection ResultsCollection = SearchDataStoreController.GetSearchResults(PortalID, Criterion.Criteria);
                        if (!Criterion.MustExclude)
                        {
                            IEnumerator refObjectHelperL1=null;
                            try
                            {
                                refObjectHelperL1 = ResultsCollection.GetEnumerator();
                                while (refObjectHelperL1.MoveNext())
                                {
                                    SearchResultsInfo Result = (SearchResultsInfo) refObjectHelperL1.Current;
                                    if (SearchResults.ContainsKey(Result.SearchItemID))
                                    {
                                        SearchResultsInfo refObjectHelperS2 = (SearchResultsInfo) SearchResults[Result.SearchItemID];
                                        refObjectHelperS2.Relevance += Result.Relevance;
                                    }
                                    else
                                    {
                                        SearchResults.Add(Result.SearchItemID, Result);
                                    }
                                }
                            }
                            finally
                            {
                                if (refObjectHelperL1 is IDisposable)
                                {
                                    (refObjectHelperL1 as IDisposable).Dispose();
                                }
                            }
                        }
                        if (Criterion.MustInclude)
                        {
                            IEnumerator refObjectHelperL3=null;
                            IEnumerator refObjectHelperL4=null;
                            Hashtable MandatoryResults = new Hashtable();
                            try
                            {
                                refObjectHelperL3 = ResultsCollection.GetEnumerator();
                                while (refObjectHelperL3.MoveNext())
                                {
                                    SearchResultsInfo result = (SearchResultsInfo) refObjectHelperL3.Current;
                                    MandatoryResults.Add(result.SearchItemID, 0);
                                }
                            }
                            finally
                            {
                                if (refObjectHelperL3 is IDisposable)
                                {
                                    (refObjectHelperL3 as IDisposable).Dispose();
                                }
                            }
                            try
                            {
                                refObjectHelperL4 = SearchResults.Values.GetEnumerator();
                                while (refObjectHelperL4.MoveNext())
                                {
                                    SearchResultsInfo Result = (SearchResultsInfo) refObjectHelperL4.Current;
                                    if (!MandatoryResults.ContainsKey(Result.SearchItemID))
                                    {
                                        Result.Delete = true;
                                    }
                                }
                            }
                            finally
                            {
                                if (refObjectHelperL4 is IDisposable)
                                {
                                    (refObjectHelperL4 as IDisposable).Dispose();
                                }
                            }
                        }
                        if (Criterion.MustExclude)
                        {
                            IEnumerator refObjectHelperL5=null;
                            IEnumerator refObjectHelperL6=null;
                            Hashtable ExcludedResults = new Hashtable();
                            try
                            {
                                refObjectHelperL5 = ResultsCollection.GetEnumerator();
                                while (refObjectHelperL5.MoveNext())
                                {
                                    SearchResultsInfo result = (SearchResultsInfo) refObjectHelperL5.Current;
                                    ExcludedResults.Add(result.SearchItemID, 0);
                                }
                            }
                            finally
                            {
                                if (refObjectHelperL5 is IDisposable)
                                {
                                    (refObjectHelperL5 as IDisposable).Dispose();
                                }
                            }
                            try
                            {
                                refObjectHelperL6 = SearchResults.Values.GetEnumerator();
                                while (refObjectHelperL6.MoveNext())
                                {
                                    SearchResultsInfo Result = (SearchResultsInfo) refObjectHelperL6.Current;
                                    if (ExcludedResults.ContainsKey(Result.SearchItemID))
                                    {
                                        Result.Delete = true;
                                    }
                                }
                            }
                            finally
                            {
                                if (refObjectHelperL6 is IDisposable)
                                {
                                    (refObjectHelperL6 as IDisposable).Dispose();
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                if (refObjectHelperL0 is IDisposable)
                {
                    (refObjectHelperL0 as IDisposable).Dispose();
                }
            }
            SearchResultsInfoCollection Results = new SearchResultsInfoCollection();
            try
            {
                refObjectHelperL7 = SearchResults.Values.GetEnumerator();
                while (refObjectHelperL7.MoveNext())
                {
                    SearchResultsInfo SearchResult = (SearchResultsInfo) refObjectHelperL7.Current;
                    TabController objTabController = new TabController();
                    if (PortalSecurity.IsInRoles(objTabController.GetTab(SearchResult.TabId).AuthorizedRoles))
                    {
                        ModuleInfo objModule = new ModuleController().GetModule(SearchResult.ModuleId, SearchResult.TabId);
                        if (PortalSecurity.IsInRoles(objModule.AuthorizedViewRoles) & !objModule.IsDeleted)
                        {
                            Results.Add(SearchResult);
                        }
                    }
                }
            }
            finally
            {
                if (refObjectHelperL7 is IDisposable)
                {
                    (refObjectHelperL7 as IDisposable).Dispose();
                }
            }
            return Results;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// GetSearchWords gets a list of the current Words in the Database's Index
        /// </summary>
        /// <remarks>
        /// </remarks>
        /// <returns>A hashtable of words</returns>
        /// <history>
        /// [cnurse]	11/15/2004	documented
        /// </history>
        /// -----------------------------------------------------------------------------
        private Hashtable GetSearchWords()
        {
            string strCacheKey = "SearchWords";
            Hashtable objWords = (Hashtable) DataCache.GetCache(strCacheKey);
            if (objWords == null)
            {
                objWords = new Hashtable();
                IDataReader drWords = DataProvider.Instance().GetSearchWords();
                try
                {
                    while (drWords.Read())
                    {
                        objWords.Add(drWords["Word"].ToString(), RuntimeHelpers.GetObjectValue(drWords["SearchWordsID"]));
                    }
                }
                finally
                {
                    drWords.Close();
                    drWords.Dispose();
                }
                DataCache.SetCache(strCacheKey, objWords, TimeSpan.FromMinutes(2.0));
            }
            return objWords;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// GetSetting gets a Search Setting from the Portal Modules Settings table (or
        /// from the Host Settings)
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// </remarks>
        /// <history>
        /// [cnurse]	11/16/2004	created
        /// </history>
        /// -----------------------------------------------------------------------------
        private string GetSetting(string txtName)
        {
            string settingValue = "";
            if (this._settings[txtName] != null)
            {
                return Conversions.ToString(this._settings[txtName]);
            }
            if (this._defaultSettings[txtName] != null)
            {
                settingValue = Conversions.ToString(this._defaultSettings[txtName]);
            }
            return settingValue;
        }

        /// -----------------------------------------------------------------------------
        /// <summary>
        /// StoreSearchItems adds the Search Item to the Data Store
        /// </summary>
        /// <remarks>
        /// </remarks>
        /// <param name="SearchItems">A Collection of SearchItems</param>
        /// <history>
        /// [cnurse]	11/15/2004	documented
        /// </history>
        /// -----------------------------------------------------------------------------
        public override void StoreSearchItems(SearchItemInfoCollection SearchItems)
        {
            this._defaultSettings = DotNetNuke.Common.Globals.HostSettings;
            Hashtable Modules = new Hashtable();
            int refIntHelperL0 = SearchItems.Count - 1;
            for (int i = 0; i <= refIntHelperL0; i++)
            {
                if (!Modules.ContainsKey(SearchItems[i].ModuleId.ToString()))
                {
                    Modules.Add(SearchItems[i].ModuleId.ToString(), "en-US");
                }
            }
            IDictionaryEnumerator moduleEnumerator = Modules.GetEnumerator();
            while (moduleEnumerator.MoveNext())
            {
                SearchItemInfo IndexedItem=null;
                SearchItemInfo SearchItem=null;
                IEnumerator refObjectHelperL0=null;
                IEnumerator refObjectHelperL1=null;
                int endLoopIntHelperS0;
                int ModuleId = Conversions.ToInteger(moduleEnumerator.Key);
                string Language = Conversions.ToString(moduleEnumerator.Value);
                SearchItemInfoCollection IndexedItems = this.GetSearchItems(ModuleId);
                SearchItemInfoCollection ModuleItems = SearchItems.ModuleItems(ModuleId);
                int iSearch = ModuleItems.Count - 1;
                goto Label_020B;
            Label_00C4:
                SearchItem = ModuleItems[iSearch];
                bool ItemFound = false;
                try
                {
                    refObjectHelperL0 = IndexedItems.GetEnumerator();
                    while (refObjectHelperL0.MoveNext())
                    {
                        IndexedItem = (SearchItemInfo) refObjectHelperL0.Current;
                        if (SearchItem.SearchKey == IndexedItem.SearchKey)
                        {
                            if (DateTime.Compare(IndexedItem.PubDate, SearchItem.PubDate) < 0)
                            {
                                try
                                {
                                    SearchItem.SearchItemId = IndexedItem.SearchItemId;
                                    SearchDataStoreController.UpdateSearchItem(SearchItem);
                                    SearchDataStoreController.DeleteSearchItemWords(SearchItem.SearchItemId);
                                    this.AddIndexWords(SearchItem.SearchItemId, SearchItem, Language);
                                }
                                catch (Exception exception1)
                                {
                    
                                    Exception ex = exception1;
                                    DotNetNuke.Services.Exceptions.Exceptions.LogException(ex);
                    
                                }
                            }
                            IndexedItems.Remove(IndexedItem);
                            ModuleItems.Remove(SearchItem);
                            ItemFound = true;
                            goto Label_01C8;
                        }
                    }
                }
                finally
                {
                    if (refObjectHelperL0 is IDisposable)
                    {
                        (refObjectHelperL0 as IDisposable).Dispose();
                    }
                }
            Label_01C8:
                if (!ItemFound)
                {
                    try
                    {
                        int IndexID = SearchDataStoreController.AddSearchItem(SearchItem);
                        this.AddIndexWords(IndexID, SearchItem, Language);
                    }
                    catch (Exception exception2)
                    {
                        ProjectData.SetProjectError(exception2);
                        Exception ex = exception2;
                        DotNetNuke.Services.Exceptions.Exceptions.LogException(ex);
        
                    }
                }
                iSearch += -1;
            Label_020B:
                endLoopIntHelperS0 = 0;
                if (iSearch >= endLoopIntHelperS0)
                {
                    goto Label_00C4;
                }
                Hashtable ht = new Hashtable();
                try
                {
                    refObjectHelperL1 = IndexedItems.GetEnumerator();
                    while (refObjectHelperL1.MoveNext())
                    {
                        IndexedItem = (SearchItemInfo) refObjectHelperL1.Current;
                        try
                        {
                            if (ht[IndexedItem.SearchItemId] == null)
                            {
                                SearchDataStoreController.DeleteSearchItem(IndexedItem.SearchItemId);
                                ht.Add(IndexedItem.SearchItemId, 0);
                            }
                        }
                        catch (Exception exception3)
                        {
                            ProjectData.SetProjectError(exception3);
                            Exception ex = exception3;
                            DotNetNuke.Services.Exceptions.Exceptions.LogException(ex);
            
                        }
                    }
                }
                finally
                {
                    if (refObjectHelperL1 is IDisposable)
                    {
                        (refObjectHelperL1 as IDisposable).Dispose();
                    }
                }
            }
        }
    }
}

